home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Scene Storm
/
Scene Storm - Volume 1.iso
/
coding
/
c
/
xvectors
/
vector0.01.c
next >
Wrap
C/C++ Source or Header
|
1995-11-05
|
9KB
|
266 lines
/****************************************************************************/
/* */
/* 3D-Rotaion Routines */
/* */
/* CrEatOr: LarZ SamuelssoN AD: 1993 */
/* */
/* If everything works as planned these routines will be based on the */
/* introduction of an Ortho-Normal-base in the vectorobject. The base, */
/* consisting of three orthogonal vectors, will then be rotated and the */
/* coordinates of the object's corners will be expressed as linear- */
/* combinations of the three base-vectors. */
/* I will also try to substitute the sine-functions with sine-tables. */
/* When calculating the perspective I will use logarithm- and */
/* exponential-tables of the natural logarithm. */
/* If I have any strenght left after these speed-ups I will look for */
/* further optimizations. */
/* */
/* I will do my best to comment the code (I need 'em too) */
/* */
/****************************************************************************/
/****************************************************************************/
/* */
/* Version 0.01: Plain ordinary rotation... calculating every new point */
/* by multiplying the rotation-matrix with the vector */
/* (SLOW) representing a corner in the object. */
/* */
/****************************************************************************/
#include <X11/Xlib.h> /* openscreen & drawing stuff */
#include <stdio.h> /* the usual I/O */
#include <math.h> /* sin() and cos() */
#include <stdlib.h>
#define CORNERS 8 /* I will be rotating a cube which has 8 corners */
#define DIM 3 /* Nr of coordinates needed to descibe a corner */
typedef float Vob[ CORNERS ][ DIM ]; /* my vector-object type */
/* Draw a line relative (ox,oy) from (x,y) to (xe, ye) on rootwindow */
void DrawLine(int x, int y, int xe, int ye, int ox, int oy);
/* Initializes the X-Crap */
void Init(void);
/* Makes X happy on exit */
void Exit(void);
/* Clear the root (I bet you never could have guessed that) */
void Cls(void);
/* Calculates and returns the corners with perspective */
Vob * Perspect(Vob * em, int depth);
/* Calculates and 'returns' the corners rotated w1,w2,w3 */
void Rotate(Vob * em, float matrix[][ DIM ]);
/* Draws the object on the rootwindow with the corners are scaled */
void DrawOb(Vob * em, int scale, int cx, int cy, int pixel);
/* These are the variables set out to explore the unknown (X) */
Display *dpy;
XColor xcolour;
GC gc;
XGCValues xgcvalues;
XSetWindowAttributes xsetwattrs;
int scrn, pixel;
int main (void)
{
int cx = 600; /* Center of rotation (rootwindow coords) */
int cy = 400;
float wx = 0; /* Step-Rotation-Angles around the axises */
float wy = 0.02;
float wz = 0;
int depth = 10; /* Perspective depth */
int scale = 200; /* Scaling factor (in pixels) */
/* This is the object we will be dealing with, hence, a cube. */
/* The numerous ones are the coordinates of the cube's corners and */
/* three unos sealed in brackets represent a vector pointing at the */
/* corner of the cube. Everything is calculated relative the center */
/* of the cube, which is located in { 0, 0, 0 } */
Vob cube =
{
{ 1, 1, 1 },
{ 1, -1, 1 },
{ 1, -1, -1 },
{ 1, 1, -1 },
{ -1, 1, -1 },
{ -1, 1, 1 },
{ -1, -1, 1 },
{ -1, -1, -1 },
};
Vob * pos; /* Holds the position of the cube's corners */
/* during the calculations */
float matrix[ DIM ][ DIM ];
/* This is the rotation-matrix for rotation around three axises */
/* and I won't explain the maths needed to understand it. */
/* Further reading: (any?) University Text about Linear Algebra */
matrix[0][0] = cos(wx) * cos(wy);
matrix[0][1] = -sin(wz) * cos(wx) - sin(wx) * sin(wy) * cos(wz);
matrix[0][2] = sin(wx) * sin(wz) - sin(wy) * cos(wx) * cos(wz);
matrix[1][0] = sin(wz) * cos(wy);
matrix[1][1] = cos(wx) * cos(wz) - sin(wx) * sin(wy) * sin(wz);
matrix[1][2] = -sin(wx) * cos(wz) - sin(wy) * sin(wz) * cos(wx);
matrix[2][0] = sin(wy);
matrix[2][1] = sin(wx) * cos(wz);
matrix[2][2] = cos(wx) * cos(wz);
Init( );
Cls( );
pos = &cube;
while (4711)
{
DrawOb( Perspect( pos, depth ), scale, cx, cy,
BlackPixel(dpy, scrn) );
/* black */
Rotate( pos, matrix );
DrawOb( Perspect( pos, depth ), scale, cx, cy,
WhitePixel(dpy, scrn) );
} /* white */
Exit( );
return 0;
}
void DrawOb(Vob * em, int scale, int cx, int cy, int pixel)
{
Vob v;
int i;
/* The mathematical cube (the one we use in our calcs) */
/* has got a sidelenght of 1+1=2, which is quite small */
/* if we consider it as pixels. Therefore we have to */
/* scale the vectors by a number, i e scale determines */
/* the on-screen-size of the cube */
for ( i=0; i<CORNERS; i++ )
{
v[i][0] = scale*(*em)[i][0];
v[i][1] = scale*(*em)[i][1];
}
/* set color */
xgcvalues.foreground = pixel;
XChangeGC (dpy,gc,GCForeground, &xgcvalues);
/* Cube specific - depends on how the cube was defined */
/* in the array declaration. If you draw a picture of */
/* the cube with it's center in oirgo (0,0,0) and plot */
/* the corners ( {1,1,1}, {1,-1,1}, etc ) it's quite */
/* easy to see which lines should be drawn. */
DrawLine(v[0][0], v[0][1], v[1][0], v[1][1], cx, cy);
DrawLine(v[1][0], v[1][1], v[2][0], v[2][1], cx, cy);
DrawLine(v[2][0], v[2][1], v[3][0], v[3][1], cx, cy);
DrawLine(v[3][0], v[3][1], v[4][0], v[4][1], cx, cy);
DrawLine(v[4][0], v[4][1], v[5][0], v[5][1], cx, cy);
DrawLine(v[5][0], v[5][1], v[6][0], v[6][1], cx, cy);
DrawLine(v[6][0], v[6][1], v[7][0], v[7][1], cx, cy);
DrawLine(v[6][0], v[6][1], v[1][0], v[1][1], cx, cy);
DrawLine(v[7][0], v[7][1], v[4][0], v[4][1], cx, cy);
DrawLine(v[5][0], v[5][1], v[0][0], v[0][1], cx, cy);
DrawLine(v[1][0], v[1][1], v[6][0], v[6][1], cx, cy);
DrawLine(v[3][0], v[3][1], v[0][0], v[0][1], cx, cy);
DrawLine(v[2][0], v[2][1], v[7][0], v[7][1], cx, cy);
}
/* This is where the perspective is calculated. I use a method where I */
/* introduce a line on parametric form from a point on the z-axis to each */
/* of the cube's corners. I let the screen be the (x,y)-plane and project */
/* the corner point on to the screen ((x,y)-plane) in the direction of the */
/* line. */
Vob * Perspect(Vob * em, int depth)
{
Vob temp;
int i;
for ( i=0; i<CORNERS; i++ )
{
temp[i][0] = (*em)[i][0]*depth/(depth-(*em)[i][2]);
temp[i][1] = (*em)[i][1]*depth/(depth-(*em)[i][2]);
}
return &temp;
}
/* This is where I multiply the matrix with the corner-vectors to yield */
/* the new corner-position. I use a temp vector to hold the values during */
/* claculation because I cannot change the 'real' values as they appear in */
/* every step of the calc. */
void Rotate(Vob * em, float matrix[][ DIM ])
{
Vob temp;
int i,j;
for ( i=0; i<CORNERS; i++ )
{
temp[i][0] = matrix[0][0]*(*em)[i][0] +
matrix[0][1]*(*em)[i][1] +
matrix[0][2]*(*em)[i][2];
temp[i][1] = matrix[1][0]*(*em)[i][0] +
matrix[1][1]*(*em)[i][1] +
matrix[1][2]*(*em)[i][2];
temp[i][2] = matrix[2][0]*(*em)[i][0] +
matrix[2][1]*(*em)[i][1] +
matrix[2][2]*(*em)[i][2];
}
for ( i=0; i<CORNERS; i++ )
for ( j=0; j<DIM; j++ )
(*em)[i][j] = temp[i][j];
}
/* Someone showed me how to initialize a screen and stuff in X so I can't */
/* explain any of the following stuff... The imprortance is that they work */
/* and the drawing routines are probably a bit different on the machines */
/* I'll be using these routines on later... */
void DrawLine(int x, int y, int xe, int ye, int ox, int oy)
{
XDrawLine(dpy, RootWindow(dpy,scrn), gc, ox+x, oy+y, ox+xe, oy+ye);
}
void Cls(void)
{
XClearWindow(dpy,RootWindow(dpy,scrn));
}
void Init(void)
{
if (!(dpy = XOpenDisplay (NULL)))
{
fprintf (stderr, "Cannot open display.\n");
exit(1);
}
scrn = DefaultScreen(dpy);
xsetwattrs.backing_store = Always;
xsetwattrs.background_pixel = BlackPixel(dpy,scrn);
pixel = WhitePixel(dpy,scrn);
XChangeWindowAttributes(dpy,RootWindow(dpy,scrn),
CWBackingStore|CWBackPixel,
&xsetwattrs);
if (XParseColor(dpy, DefaultColormap(dpy,scrn), "khaki2", &xcolour))
if (XAllocColor (dpy, DefaultColormap(dpy,scrn), &xcolour))
pixel = xcolour.pixel;
gc = XCreateGC (dpy, RootWindow(dpy,scrn),0,NULL);
}
void Exit(void)
{
XFlush (dpy);
}